package com.mazaiting.instructions.stack;

import com.mazaiting.instructions.base.NoOperandsInstruction;
import com.mazaiting.rtda.MtFrame;
import com.mazaiting.rtda.MtOperandStack;
import com.mazaiting.rtda.MtSlot;

/**
 * 复制指令
 *
 * @author mazaiting
 * @since 2021/8/14
 */
public class DupInstruction {

    /**
     * 复制栈顶的单个变量
     * bottom -> top
     * [...][c][b][a]
     *              \_
     *                |
     *                V
     * [...][c][b][a][a]
     */
    public static class Dup extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            MtSlot slot = stack.popSlot();
            stack.pushSlot(slot);
            stack.pushSlot(slot);
        }
    }

    /**
     * 复制栈顶的单个变量并且插入到两个值之后
     * bottom -> top
     * [...][c][b][a]
     *           __/
     *          |
     *          V
     * [...][c][a][b][a]
     */
    public static class DupX1 extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            MtSlot slot1 = stack.popSlot();
            MtSlot slot2 = stack.popSlot();
            stack.pushSlot(slot1);
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
        }
    }

    /**
     * 复制栈顶的单个变量并且插入到三个值之后
     * bottom -> top
     * [...][c][b][a]
     *        _____/
     *       |
     *       V
     * [...][a][c][b][a]
     */
    public static class DupX2 extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            MtSlot slot1 = stack.popSlot();
            MtSlot slot2 = stack.popSlot();
            MtSlot slot3 = stack.popSlot();
            stack.pushSlot(slot1);
            stack.pushSlot(slot3);
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
        }
    }

    /**
     * 复制栈顶的两个字节变量
     * [...][c][b][a]____
     *           \____   |
     *                |  |
     *                V  V
     * [...][c][b][a][b][a]
     */
    public static class Dup2 extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            MtSlot slot1 = stack.popSlot();
            MtSlot slot2 = stack.popSlot();
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
        }
    }

    /**
     * 复制栈顶的两个字节变量并且插入到第二值之后
     * bottom -> top
     * [...][c][b][a]
     *        _/ __/
     *       |  |
     *       V  V
     * [...][b][a][c][b][a]
     */
    public static class Dup2X1 extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            MtSlot slot1 = stack.popSlot();
            MtSlot slot2 = stack.popSlot();
            MtSlot slot3 = stack.popSlot();
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
            stack.pushSlot(slot3);
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
        }
    }

    /**
     * 复制栈顶的两个字节变量并且插入到第三值之后
     * bottom -> top
     * [...][d][c][b][a]
     *        ____/ __/
     *       |   __/
     *       V  V
     * [...][b][a][d][c][b][a]
     */
    public static class Dup2X2 extends NoOperandsInstruction {
        @Override
        public void execute(MtFrame frame) {
            MtOperandStack stack = frame.getOperandStack();
            MtSlot slot1 = stack.popSlot();
            MtSlot slot2 = stack.popSlot();
            MtSlot slot3 = stack.popSlot();
            MtSlot slot4 = stack.popSlot();
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
            stack.pushSlot(slot4);
            stack.pushSlot(slot3);
            stack.pushSlot(slot2);
            stack.pushSlot(slot1);
        }
    }

}
